package com.sudo.boot.admin.aspect;

import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.StpInterface;
import cn.dev33.satoken.stp.StpUtil;
import com.boot.starter.redis.component.RedisKeys;
import com.mybatisflex.core.query.QueryWrapper;
import com.sudo.boot.base.constant.SsoConstant;
import com.sudo.boot.base.constant.enums.EnumStatus;
import com.sudo.boot.base.constant.enums.EnumYesNo;
import com.sudo.boot.base.exception.BizException;
import com.sudo.boot.mapper.sys.entity.SysRole;
import com.sudo.boot.mapper.sys.entity.SysUser;
import com.sudo.boot.mapper.sys.entity.SysUserRole;
import com.sudo.boot.mapper.sys.mapper.SysRoleMapper;
import com.sudo.boot.mapper.sys.mapper.SysUserMapper;
import com.sudo.boot.mapper.sys.mapper.SysUserRoleMapper;
import com.sudo.boot.satokensso.util.SaRedisUtil;
import com.sudo.boot.service.sys.SysMenuService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.util.*;

import static com.sudo.boot.mapper.sys.entity.table.SysRoleTableDef.SYS_ROLE;
import static com.sudo.boot.mapper.sys.entity.table.SysUserRoleTableDef.SYS_USER_ROLE;
import static com.sudo.boot.mapper.sys.entity.table.SysUserTableDef.SYS_USER;

/**
 * 权限校验
 *
 * @author DayDayUp
 * @datetime 2023-11-13 9:53
 **/
@Component
public class StpInterfaceImpl implements StpInterface {
    @Resource
    private SaRedisUtil saRedisUtil;
    @Resource
    private SysRoleMapper sysRoleMapper;
    @Resource
    private SysUserMapper sysUserMapper;
    @Resource
    private SysUserRoleMapper sysUserRoleMapper;
    @Resource
    private SysMenuService sysMenuService;
    /**
     * StpUtil.hasPermission(10001, "user_add"); 会走该方法
     * 针对 StpUtil.hasPermission(10001, "user_add"); 只获取当前用户权限，如果未登录则获取默认权限
     */
    @Override
    public List<String> getPermissionList(Object loginId, String loginType) {
        // 判断该用户session是否存在
        String tokenValue = StpUtil.getTokenValueByLoginId(loginId);
        if (StringUtils.hasText(tokenValue)) {
            // 从缓存中查询，如果redis中不存在，则从库中查询并放入redis
            SaSession saSession = StpUtil.getSessionByLoginId(loginId);
            checkLoginUser(saSession);
            String currRole = checkAndGetLoginRole(saSession);
            return sysMenuService.getRoleButtonList(currRole);
        }else {
            // 从库中查询
            String roleCode = checkAndGetUnLoginUser(String.valueOf(loginId));
            return sysMenuService.getRoleButtonList(roleCode);
        }
    }

    /**
     * StpUtil.hasRole(10001, "super-admin"); 会走该方法
     */
    @Override
    public List<String> getRoleList(Object loginId, String loginType) {
        SysUser sysUser = sysUserMapper.selectOneByCondition(SYS_USER.USERNAME.eq(loginId));
        Assert.notNull(sysUser, "用户【" + loginId + "】不存在");

        List<SysUserRole> userRoleList = sysUserRoleMapper.selectListByCondition(SYS_USER_ROLE.USERNAME.eq(loginId));
        return userRoleList.stream().map(SysUserRole::getRoleCode).toList();
    }


    private String checkAndGetLoginRole(SaSession session) {
        String currRole = (String)session.get(SsoConstant.currRoleCode);
        if (!StringUtils.hasText(currRole)) {
            throw new BizException("当前角色不存在，请切换角色");
        }
        String roleStatusKey = RedisKeys.roleStatus(currRole);
        Object roleStatus = saRedisUtil.get(roleStatusKey);
        if (Objects.nonNull(roleStatus)) {
            if (!EnumStatus.ON.getCode().equals(roleStatus)) {
                throw new BizException("当前角色已禁用，请切换角色");
            }
        }else {
            // 加载数据库角色
            SysRole sysRole = sysRoleMapper.selectOneByCondition(SYS_ROLE.ROLE_CODE.eq(currRole));
            if (Objects.isNull(sysRole)) {
                throw new BizException("该角色不存在，请联系管理员");
            }else {
                saRedisUtil.set(roleStatusKey,sysRole.getStatus());
                if (!EnumStatus.ON.getCode().equals(sysRole.getStatus())) {
                    throw new BizException("当前角色已禁用，请切换角色");
                }
            }
        }
        return currRole;
    }

    private void checkLoginUser(SaSession session) {
        String currUserStatus = (String) session.get(SsoConstant.currUserStatus);
        String currUsername = (String) session.getLoginId();
        if (StringUtils.hasText(currUserStatus)) {
            if (!EnumStatus.ON.getCode().equals(currUserStatus)) {
                throw new BizException("该账号已锁定");
            }
        }else {
            SysUser sysUser = sysUserMapper.selectOneByCondition(SYS_USER.USERNAME.eq(currUsername));
            if (Objects.isNull(sysUser)) {
                throw new BizException("该账号不存在");
            }else {
                session.set(SsoConstant.currUserStatus, sysUser.getStatus());
                if (!EnumStatus.ON.getCode().equals(sysUser.getStatus())) {
                    throw new BizException("该账号已锁定");
                }
            }
        }
    }


    private String checkAndGetUnLoginUser(String loginId) {
        QueryWrapper queryWrapper = QueryWrapper.create()
                .where(SYS_USER_ROLE.DEFAULT_ROLE.eq(EnumYesNo.YES.getCode()))
                .and(SYS_USER_ROLE.USERNAME.eq(loginId));
        SysUserRole sysUserRole = sysUserRoleMapper.selectOneByQuery(queryWrapper);

        Assert.notNull(sysUserRole, "用户【" + loginId + "】不存在");
        return sysUserRole.getRoleCode();
    }
}
